#include "mainwindow.h"
#include "mainwindow_utils.h"
#include "ui_mainwindow.h"
#include <cstdio>
#define  Qconnect QObject::connect

void MainWindow::init_eq(void)
{
    if (is_equalizer_present)
    {
        eq = new Equalizer(this);
        eq->setAllowedAreas(Qt::AllDockWidgetAreas);
        addDockWidget(Qt::RightDockWidgetArea, eq, Qt::Horizontal);
        Qconnect(eq, SIGNAL(update_channels()), this, SLOT(slot_set_eq()));
        if (hndl)
            for (int i = 0; i < EQS_MAX; i++)
                engine_equalizer_init(hndl, eq->_fxs[i]);
    }
}

void MainWindow::init_vis(void)
{
    visualizator = NULL;
    if (this->is_visualizator_present)
    {
        visualizator = new vis_draw(this);
        visualizator->setAllowedAreas(Qt::AllDockWidgetAreas);
        addDockWidget(Qt::TopDockWidgetArea, visualizator, Qt::Horizontal);
        Qconnect(&dr_timer, SIGNAL(timeout()), this, SLOT(slot_repaint(void)));
        if (!mywave)
            mywave = new unsigned[MYWAVE_LEN];
        if (!myfft)
            myfft = new float[MYFFT_LEN];
        visualizator->init(mywave, myfft, MYWAVE_LEN, MYFFT_LEN);
    }

}

void MainWindow::init_playlist(void)
{
    view = NULL;
    tags = NULL;

    is_cover_present = true;
    is_tags_present = false;
    playlist = new plst(NULL, &view, &tags, &pl_timer,&dr_timer);
    playlist->show();
    centralWidget()->layout()->addWidget(playlist);
}

#define PLAY_DEBUG
#define NO_ENGINE
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    hndl = 0;
    MYFFT_LEN = 1024;
    MYWAVE_LEN = 2048;
    mywave = NULL;
    myfft = NULL;

    playb_sliding = false;
    paused = false;
    is_visualizator_present = false;
    is_equalizer_present = false;

    is_cover_present = false;
    is_tags_present = false;

    if (!engine_init())
    {
        qDebug("can`t initilize audio-engine...");
        qDebug("Current Audio engine:BASS");
        abort();
    }
    ui->setupUi(this);

    init_playlist();
    init_connections();
    init_timers();
    init_eq();
    init_vis();
    init_volume();
#ifdef PLAY_DEBUG
    //playlist->add_fileqs("/windows/D/Music/FMP_OST/Sore_Ga_Ai_Deshou.mp3");
    //QString str = "/home/lberserq/tmp/ad/Anime_Song_Orchestra_II.cue";
    QString str = "/windows/D/Music/Chrno Crusade Music Collection/Chrno Crusade OP Single - Tsubasa wa Pleasure Line/Tsubasa_wa_Pleasure_Line-UTF-8.cue";
    playlist->load_cue(str);
    slot_play();
#endif
}

void MainWindow::init_volume(void)
{
    ui->volume_slider->setSliderPosition(0.0);
    slot_volume();
}

void MainWindow::init_timers(void)
{
    pl_timer.setInterval(300);
    dr_timer.setInterval(33);
}

void MainWindow::init_connections(void)
{
    Qconnect(ui->btn_play, SIGNAL(clicked()),this, SLOT(slot_play(void)));
    Qconnect(ui->btn_stop, SIGNAL(clicked()),this, SLOT(slot_stop(void)));
    Qconnect(ui->btn_pause, SIGNAL(clicked()), this, SLOT(slot_pause(void)));
    Qconnect(ui->btn_Add, SIGNAL(clicked()), playlist, SLOT(slot_file_add(void)));
    Qconnect(ui->btn_prev, SIGNAL(clicked()), this, SLOT(slot_play_prev(void)));
    Qconnect(ui->btn_nxt, SIGNAL(clicked()), this, SLOT(slot_play_next(void)));
    Qconnect(ui->volume_slider, SIGNAL(sliderMoved(int)), this, SLOT(slot_volume(void)));
    Qconnect(ui->volume_slider, SIGNAL(valueChanged(int)), this, SLOT(slot_volume(void)));
    Qconnect(ui->volume_slider, SIGNAL(sliderPressed()), this, SLOT(slot_volume(void)));
    Qconnect(ui->volume_slider, SIGNAL(sliderReleased()), this, SLOT(slot_volume(void)));


    Qconnect(ui->time_slider, SIGNAL(sliderMoved(int)), this, SLOT(slot_pos_move(void)));

    Qconnect(ui->time_slider, SIGNAL(sliderPressed()), this, SLOT(slot_slide_start(void)));
    Qconnect(ui->time_slider, SIGNAL(sliderReleased()), this, SLOT(slot_slide_stop(void)));
    Qconnect(&pl_timer, SIGNAL(timeout()), this, SLOT(slot_playb_timer(void)));
    Qconnect(playlist, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(slot_plst_dblclk(QListWidgetItem*)));

    Qconnect(ui->actionFile, SIGNAL(activated()), playlist, SLOT(slot_file_add(void)));
    Qconnect(ui->actionFileO, SIGNAL(activated()), playlist, SLOT(slot_file_open(void)));
    //Qconnect(ui->actionFileO, SIGNAL(activated()), this, SLOT(slot_stop()));


    Qconnect(ui->actionFolder, SIGNAL(activated()), playlist, SLOT(slot_dir_add(void)));
    Qconnect(ui->actionFolderO, SIGNAL(activated()), playlist, SLOT(slot_dir_open(void)));
   // Qconnect(ui->actionFolderO, SIGNAL(activated()), this, SLOT(slot_stop(void)));

    Qconnect(ui->actionPlaylist, SIGNAL(activated()), playlist, SLOT(slot_playlist_add(void)));
    Qconnect(ui->actionPlaylistO, SIGNAL(activated()), playlist, SLOT(slot_playlist_open(void)));
    //Qconnect(ui->actionPlaylistO, SIGNAL(activated()), this, SLOT(slot_stop(void)));

    Qconnect(ui->actionSave_Playlist, SIGNAL(activated()), playlist, SLOT(slot_playlist_save(void)));


    Qconnect(ui->actionSettingsVisualizer, SIGNAL(toggled(bool)), this, SLOT(slot_visualizator_toogle(bool)));
    Qconnect(ui->actionSettingsEqualizer, SIGNAL(toggled(bool)), this, SLOT(slot_equalizer_toogle(bool)));

    Qconnect(ui->actionSettingsCover, SIGNAL(toggled(bool)), this, SLOT(slot_cover_toogle(bool)));
    Qconnect(ui->actionSettingsTags, SIGNAL(toggled(bool)), this, SLOT(slot_tags_toogle(bool)));
    //Qconnect(this, SIGNAL())
}


void MainWindow::keyReleaseEvent(QKeyEvent *e)
{
    qDebug("key code pressed %d",e->key());
    switch(e->key())
    {
    case Qt::Key_Space: slot_pause(); break;
    case Qt::Key_Delete :playlist->delete_selected(); break;
    case Qt::Key_Enter: slot_play();
    }
}

//--------------------------------------------SLOTS---------------------------------
//----------------------------------------------PLAYBACK SLOTS--------------------------------------------

void MainWindow::slot_visualizator_toogle(bool state)
{
    is_visualizator_present = state;
    if (state)
    {
        init_vis();
        if (hndl)
            dr_timer.start();
    }
    else
    {
        dr_timer.stop();
        if (visualizator)
            delete visualizator;
        if (mywave)
            delete mywave;
        if (myfft)
            delete myfft;
        visualizator = NULL;
        mywave = NULL;
        myfft = NULL;
    }
}



void MainWindow::slot_equalizer_toogle(bool state)
{
    is_equalizer_present = state;
    if (state)
        init_eq();
    else
    {
        if (eq)
            delete eq;
        eq = NULL;
    }
}


void MainWindow::slot_cover_toogle(bool state)
{
    is_cover_present = state;
    if (is_cover_present)
    {
        view =  new QGraphicsView();
        playlist->slot_cover_update();
    }
    else
    {
        if (view)
            delete view;
        view = NULL;
    }
}



#define FIELDS_NUM 7
const char* nms[FIELDS_NUM] = {"Artist Name", "Track Title", "Album Title", "Date", "Genre", "Track Number", "Comment"};


void MainWindow::slot_tags_toogle(bool state)
{
    is_tags_present = state;
    if (state)
    {
        tags = new QTableWidget(FIELDS_NUM, 2);
        QStringList lst;
        lst << "Name" << "Value";
        tags->setHorizontalHeaderLabels(lst);
        for (int i = 0; i < FIELDS_NUM; i++)
        {
            QTableWidgetItem *pitem = new QTableWidgetItem();
            QString txt = nms[i];
            pitem->setText(txt);
            tags->setItem(i, 0, pitem);
            //Qconnect(tags, SIGNAL())
        }

        playlist->slot_tagwidget_update();
    }
    else
    {
        if (tags)
            delete tags;
        tags = NULL;
    }
}

void MainWindow::slot_pause(void)
{
    if (hndl)
    {
        if (paused)
            engine_channel_play(hndl, false);
        else
            engine_channel_pause(hndl);
        paused = !paused;
    }
}

void MainWindow::slot_play(void)
{
    play(playlist->get_file_name());
}


void MainWindow::slot_stop(void)
{
    if (pl_timer.isActive())
        pl_timer.stop();
    if (dr_timer.isActive())
        dr_timer.stop();
    ui->time_slider->setValue(0);
    if (hndl)
        engine_channel_terminate(hndl);
    hndl = 0;
    MainWindow::setWindowTitle("preplayer 0.001");
}
//--------------------------------------------PLaylist------------------------------------

void MainWindow::slot_plst_dblclk(QListWidgetItem *item)
{
    play(playlist->get_file_name());
}

//-----------------------------------SLIDERS----------------------------------------------
void MainWindow::slot_volume(void)
{
    char str[512];
    sprintf(str, "Volume changed %d %%",ui->volume_slider->sliderPosition());
    MainWindow::setWindowTitle(str);
    float vl = float(ui->volume_slider->sliderPosition()) / 100;
    engine_set_volume(this->hndl, vl);
}

void MainWindow::slot_pos_move(void)
{
    if (!playb_sliding && hndl)
    {
        QWORD pos = engine_channel_seconds2bytes(hndl, ui->time_slider->value());
        engine_channel_setposition(hndl, pos, ENGINE_POS_BYTE);
        playb_sliding = false;
    }
    char ch[512];
    sprintf(ch, "CPU: %.2f%%; time %02d:%02d//%02d:%02d", engine_get_cpu(), ui->time_slider->value() / 60,
            ui->time_slider->value() % 60, ui->time_slider->maximum() / 60, ui->time_slider->maximum()% 60);
    MainWindow::setWindowTitle(ch);
}



void MainWindow::slot_slide_start()
{
    pl_timer.stop();
    playb_sliding = true;
}

void MainWindow::slot_slide_stop()
{
    playb_sliding = false;
    slot_pos_move();
    pl_timer.start();
}


//---------------------------------------TIMER--------------------------------------------------------------

void MainWindow::pl_timer_run()
{
    if (!pl_timer.isActive())
        pl_timer.start();
    if (!dr_timer.isActive())
        dr_timer.start();

}

void MainWindow::pl_timer_stop()
{
    if (pl_timer.isActive())
        pl_timer.stop();
    if (dr_timer.isActive())
        dr_timer.stop();
}


void MainWindow::slot_playb_timer(void)
{
    if (playb_sliding)
        return;
    int time_val = ui->time_slider->value();
    ui->time_slider->setValue(floor(engine_channel_bytes2seconds(hndl, engine_channel_getposition(hndl, ENGINE_POS_BYTE))) -
                              playlist->get_at(playlist->currentRow()).startpos);
    char ch[512];
    if (floor(engine_get_cpu()) > 70.0)
    {
        qDebug("Your system so slow to play this or engine is corrupted");
        qDebug("Restart player if this problem appear contact to developer");
        this->close();
        this->~MainWindow();
        return;
    }
    sprintf(ch, "CPU: %.2f%%; time %02d:%02d//%02d:%02d", engine_get_cpu(), ui->time_slider->value() / 60,
            ui->time_slider->value() % 60, ui->time_slider->maximum() / 60, ui->time_slider->maximum()% 60);
    if (time_val == ui->time_slider->maximum())
    {
        slot_stop();
        slot_play_next();
    }
    MainWindow::setWindowTitle(ch);
}
///--------------------------------------------------------END------------OF-----------SLOTS---------------------------------
///--------------------------NEXT------------------AND-----------PREV--------------------------------------------------------


void MainWindow::play(QString str)
{

    pl_tag tg = playlist->get_at(playlist->currentRow());
    if (tg.fname.isEmpty()|| tg.fname.isNull()) {
        perror("Bad filename or incorrect encoding ");
        return;
    }

    this->slot_stop();
    char *fname = str_decode(str);

    hndl = engine_channel_create(str_decode(tg.fname), true);


    if (!hndl)// All things are bad die
    {
        perror("Can`t create stream ");
        fprintf(stderr, "%s\n", str_decode(tg.fname));
        abort();
    }
    ui->time_slider->setMaximum(tg.duration);
    ui->time_slider->setValue(0);
    QWORD pos = engine_channel_seconds2bytes(hndl, tg.startpos);
    engine_channel_setposition(hndl, pos, ENGINE_POS_BYTE);
    engine_channel_play(hndl, false);

    if (is_equalizer_present)
        for (int i = 0; i < EQS_MAX; i++)
            engine_equalizer_init(hndl, eq->_fxs[i]);
    playlist->slot_cover_update();
    playlist->slot_tagwidget_update();
    if (pl_timer.interval() != 0)
        pl_timer.start();
    if (is_visualizator_present && (dr_timer.interval() != 0))
        dr_timer.start();
    if (fname != NULL)
        delete fname;
}


void MainWindow::slot_play_next(void)
{
    slot_stop();
    int id = playlist->currentRow();
    if (ui->rnchk->checkState())
        id =  rand() % playlist->count();
    else
        if (ui->cycle_chk->checkState())
            id = (id + 1) % playlist->count();
        else
            if (id < (playlist->count() - 1))
                id++;
            else
                return;
    playlist->setCurrentRow(id);
    play(playlist->get_file_byid(id));
}

void MainWindow::slot_set_eq(void)
{
    if (is_equalizer_present)
        for (int i = 0; i < EQS_MAX; i++)
            engine_equalizer_setfreq(eq->_fxs[i], eq->eqs[i]->hz, eq->eqs[i]->val);
}


void MainWindow::slot_play_prev(void)
{
    int id = playlist->currentRow();
    if (ui->rnchk->checkState())
        id =  rand() % playlist->count();
    else
        if (ui->cycle_chk->checkState())
            id = (playlist->count() + id - 1) % playlist->count();
        else
            if (id > 0)
                id--;
            else
                return;

    playlist->setCurrentRow(id);
    play(playlist->get_file_byid(id));
}

void MainWindow::slot_repaint(void)
{
    if (is_visualizator_present)
    {
        engine_channel_getdata(hndl, mywave, MYWAVE_LEN);
        engine_channel_getdata(hndl, myfft, ENGINE_FFT1024);
        visualizator->d_repaint();
    }
}
//-----------------------------------------------DESTRUCTOR----------------------------------------------------
MainWindow::~MainWindow()
{
    engine_free_allplugins();
    engine_free();
    if (playlist)
        delete playlist;
    if (is_tags_present)
    {
        if (tags)
        {
            tags->close();
            delete tags;
        }
    }

    if (is_cover_present)
    {
        if (view)
        {
            view->close();
            delete view;
        }

    }

    if (is_equalizer_present)
        delete eq;
    if (is_visualizator_present)
    {
        if (mywave)
            delete [] mywave;
        if (myfft)
            delete [] myfft;
        if (visualizator)
            delete visualizator;
    }
    //delete ui;
}
